﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class 序列反射動態程式集_反射表达式树DLR性能对比 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {


        //填充数据
        Action act = () => { InitTypePropertyAssignExpression<TestCalass>(true); };


        Response.Write("转换完成:" + act.StopwatchRun() + "毫秒<br/>");


        List<double> lis = new List<double>() { 0.1, 0.5, 10, 20, 30, 50, 100, 200 };

        //不同循环次数对比
        foreach (double num in lis)
        {

            RunDiff(num);
        }

    }


    #region 填充与计算方法

    Random dom = new Random();
    /// <summary>
    /// 开始比较方法
    /// </summary>
    /// <param name="num">进行多少次比较</param>
    public void RunDiff(double num = 10)
    {
        //10万次计算时间对比
        var arr = System.Linq.Enumerable.Range(1, (int)(num * 10000)).ToList();



        Action 手动编码 = () =>
        {
            arr.ForEach((o) =>
            {
                TestCalass c = new TestCalass();
                产生随机值并且填充对像(c, 2);
            });
        };

        Action 表达式树 = () =>
        {
            arr.ForEach((o) =>
            {
                TestCalass c = new TestCalass();
                产生随机值并且填充对像(c, 0);

            });
        };


        Action 反射 = () =>
        {
            arr.ForEach((o) =>
            {
                TestCalass c = new TestCalass();
                产生随机值并且填充对像(c, 1);
            });
        };

        long v0, v1, v2;

        Response.Write(string.Format("{0} 运行 {1} 万次,用时{2}毫秒<br/>", "手动编码", arr.Count / 10000.0, v2 = 手动编码.StopwatchRun()));
        Response.Write(string.Format("{0} 运行 {1} 万次,用时{2}毫秒<br/>", "表达式树", arr.Count / 10000.0, v0 = 表达式树.StopwatchRun()));
        Response.Write(string.Format("{0} 运行 {1} 万次,用时{2}毫秒<br/>", "反射赋值", arr.Count / 10000.0, v1 = 反射.StopwatchRun()));
        Response.Write(string.Format("{0}为基准值 {1}用时{2};   {3}用时{4}  相差:{5},快了{6}倍 <br/>", v2, "表达式树", v0 - v2, "反射赋值", v1 - v2, (v1 - v0), (v1 - v0) / (v0 - v2)));
        Response.Write(string.Format("--------------------------<br/>"));

    }

    /// <summary>
    /// 设置反射数据
    /// </summary>
    public void RefSetvalue(System.Reflection.PropertyInfo p, TestCalass t, object val)
    {
        p.SetValue(t, val, null);
    }

    public void 产生随机值并且填充对像(TestCalass c, int isExpression = 1)
    {
        foreach (var p in exProinfoDic)
        {

            if (p.Value.PropertyType == typeof(int))
            {
                int val = dom.Next(1, int.MaxValue);
                //是否使用表达式赋值
                switch (isExpression)
                {
                    case 0:
                        //传值
                        p.Value.ActionAssign(val, c);
                        break;
                    case 1:

                        RefSetvalue(p.Value.PropertyInfo, c, val);
                        break;

                    case 2:
                        c.a = val;
                        break;

                }
                continue;

            }


            if (p.Value.PropertyType == typeof(string))
            {
                string val = Guid.NewGuid().ToString();
                //是否使用表达式赋值
                switch (isExpression)
                {
                    case 0:
                        //传值
                        p.Value.ActionAssign(val, c);
                        break;
                    case 1:

                        RefSetvalue(p.Value.PropertyInfo, c, val);
                        break;

                    case 2:
                        c.b = val;
                        break;

                }
                continue;

            }

            if (p.Value.PropertyType == typeof(DateTime))
            {
                int vald = dom.Next(1, int.MaxValue);
                DateTime val = DateTime.Now.AddMilliseconds(vald);
                //是否使用表达式赋值
                switch (isExpression)
                {
                    case 0:
                        //传值
                        p.Value.ActionAssign(val, c);
                        break;
                    case 1:

                        RefSetvalue(p.Value.PropertyInfo, c, val);
                        break;

                    case 2:
                        c.c = val;
                        break;


                }
                continue;
            }

            if (p.Value.PropertyType == typeof(double[]))
            {
                double[] val = new double[50];
                for (int i = 0; i < val.Length; i++)
                {
                    val[i] = dom.Next(1, int.MaxValue);
                }
                //是否使用表达式赋值
                switch (isExpression)
                {
                    case 0:
                        //传值
                        p.Value.ActionAssign(val, c);
                        break;
                    case 1:

                        RefSetvalue(p.Value.PropertyInfo, c, val);
                        break;

                    case 2:
                        c.Arr = val;
                        break;

                }
                continue;

            }

        }
    }

    #endregion



    /// <summary>
    /// 初始化类型属性表达式操作,只能处理基元类型
    /// </summary>
    ///<exception cref="System.Collections.Generic.KeyNotFoundException">没有找到合适的处理方法</exception>
    ///<param name="NotFindConvertObject">没有找到合适类型自动转换成为object</param>
    public void InitTypePropertyAssignExpression<T>(bool NotFindConvertObject = false)
    {
        //初始化表达式
        foreach (var p in typeof(T).GetProperties())
        {
            //C# 所有基元类型
            if (CreateExpression<T, byte>(p)) { continue; }
            if (CreateExpression<T, sbyte>(p)) { continue; }
            if (CreateExpression<T, int>(p)) { continue; }
            if (CreateExpression<T, uint>(p)) { continue; }
            if (CreateExpression<T, short>(p)) { continue; }
            if (CreateExpression<T, ushort>(p)) { continue; }
            if (CreateExpression<T, long>(p)) { continue; }
            if (CreateExpression<T, ulong>(p)) { continue; }
            if (CreateExpression<T, float>(p)) { continue; }
            if (CreateExpression<T, double>(p)) { continue; }
            if (CreateExpression<T, char>(p)) { continue; }
            if (CreateExpression<T, bool>(p)) { continue; }
            if (CreateExpression<T, string>(p)) { continue; }
            if (CreateExpression<T, decimal>(p)) { continue; }
            if (CreateExpression<T, object>(p)) { continue; }
            if (CreateExpression<T, DateTime>(p)) { continue; }

            if (NotFindConvertObject)
            {
                //没有找到合适的类型自动转换成为object
                CreateExpression<T, object>(p, true);
            }
            else
            {
                throw new KeyNotFoundException("没有找到合适的基元类型");

            }
        }
    }

    /// <summary>
    /// 创建属性表达式数据实体
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    /// <typeparam name="TValue">属性的 值类型</typeparam>
    /// <param name="p">属性信息</param>
    /// <param name="toObject">转换成为Object</param>
    /// <returns>成功返回true</returns>
    protected bool CreateExpression<T, TValue>(System.Reflection.PropertyInfo p, bool toObject = false)
    {

        if (p.PropertyType == typeof(TValue) || toObject)
        {
            //添加到缓存集合
            return exProinfoDic.TryAdd(p.Name, new ExpressionPropertyInfo()
             {
                 PropertyType = p.PropertyType,
                 PropertyName = p.Name,
                 PropertyInfo = p,
                 ActionAssign = GetExpression<T, TValue>(p.Name)
             });
        }



        return false;
    }

    /// <summary>
    /// 表达式类型属性信息对像缓存
    /// </summary>
    System.Collections.Concurrent.ConcurrentDictionary<string, ExpressionPropertyInfo> exProinfoDic = new System.Collections.Concurrent.ConcurrentDictionary<string, ExpressionPropertyInfo>();


    /// <summary>
    /// 一个属性传值操作 表达式
    /// </summary>
    /// <param name="propertyName">属性名</param>
    /// <typeparam name="T">实体类型值</typeparam>
    /// <typeparam name="TValue">属性类型值</typeparam>
    /// <returns></returns>
    public Func<TValue, T, TValue> GetExpression<T, TValue>(string propertyName)
    {
        Type t = typeof(T);
        System.Reflection.PropertyInfo pro = t.GetProperty(propertyName);
        return GetExpression<T, TValue>(pro);
    }

    /// <summary>
    /// 一个属性传值操作 表达式
    /// </summary>
    /// <param name="propertyInfo">属性对像</param>
    /// <typeparam name="T">实体类型值</typeparam>
    /// <typeparam name="TValue">属性类型值</typeparam>
    /// <returns></returns>
    public Func<TValue, T, TValue> GetExpression<T, TValue>(System.Reflection.PropertyInfo propertyInfo)
    {
        Type t = typeof(T);
        Type vt = typeof(TValue);
        //参数p
        System.Linq.Expressions.ParameterExpression p = System.Linq.Expressions.Expression.Parameter(t, "p");
        //参数值 v
        System.Linq.Expressions.ParameterExpression v = System.Linq.Expressions.Expression.Parameter(vt, "v");

        //属性 curp
        System.Linq.Expressions.MemberExpression curP = System.Linq.Expressions.Expression.Property(p, propertyInfo);


        //赋值操作
        System.Linq.Expressions.BinaryExpression ass = null;
        if (vt != propertyInfo.PropertyType)
        {
            //转换表达式 v
            System.Linq.Expressions.UnaryExpression conv = System.Linq.Expressions.Expression.Convert(v, propertyInfo.PropertyType);
            //赋值操作
            ass = System.Linq.Expressions.Expression.Assign(curP, conv);

        }
        else
        {
            ass = System.Linq.Expressions.Expression.Assign(curP, v);
        }


        //表达式结果
        System.Linq.Expressions.Expression<Func<TValue, T, TValue>> result = System.Linq.Expressions.Expression.Lambda<Func<TValue, T, TValue>>(ass, v, p);

        //返回编译后结果
        return result.Compile();

    }



    /// <summary>
    /// 表达式类型属性信息对像
    /// </summary>
    public class ExpressionPropertyInfo
    {
        /// <summary>
        /// 属性名
        /// </summary>
        public string PropertyName { get; set; }

        /// <summary>
        /// 属性类型
        /// </summary>
        public Type PropertyType { get; set; }

        /// <summary>
        /// 属性对像
        /// </summary>
        public System.Reflection.PropertyInfo PropertyInfo { get; set; }

        /// <summary>
        /// 赋值操作委托
        /// </summary>
        public dynamic ActionAssign { get; set; }

    }

    /// <summary>
    /// 测试用类
    /// </summary>
    public class TestCalass
    {
        public int a { get; set; }

        public string b { get; set; }

        public DateTime c { get; set; }

        public double[] Arr { get; set; }

    }
}